MODULE = PlPN          PACKAGE = PlPN::Options

#
# Pod::Html is kind of brain-dead:
#
# Place Z<> between function names and parentheses, otherwise Pod::Html
# assumes you meant to put C<...> around it
#
# Put explicit text in all links L<use my text, stupid|some::perl::module>,
# otherwise Pod::Html assumes you want "the X manpage". (Does not apply to
# relative links withing this file.)
#
# It also assumes you want a link if you have C<...> with text matching a
# potential link target. The only way I've found around that is to split it
# up into multiple pieces: C<wo>C<rd>. Looks correct in the resulting HTML,
# but it's ugly to have <code>wo</code><code>rd</code> in the source, and I
# shouldn't have to do it.
#

=head1 NAME

PlPN::Options - The options manager object

=head1 SYNOPSIS

	use PlPN qw(PN TRUE FALSE :OptionsGroup :ECachedOption :PNPath);
	
	my $om = PN->GetOptionsManager;
	my $value = $om->Get($group, $name, $default);
	my $pn_path = $om->GetPNPath;
	
	# etc.

=head1 DESCRIPTION

Allows access and editing of Programmer's Notepad settings from Perl.

=cut

FALLBACK: TRUE

bool
eq(a,b,swap)
		extensions::IOptions* a;
		extensions::IOptions* b;
		IV swap;
	OVERLOAD: ==
	CODE:
		RETVAL = (a == b);
	OUTPUT:
		RETVAL

#
# xsubpp only generates the following code for the module, not for the
# individual packages. In our case, that's less than useful, because the
# module does not, in fact, have overloaded operators.
# See the boot section in the generated code for an explanation of what the
# following code does
#
BOOT:
PL_amagic_generation++;
sv_setsv(
	get_sv( "PlPN::Options::()", TRUE ),
	&PL_sv_yes	// or &PL_sv_no or &PL_sv_undef
);
(void)newXSproto_portable("PlPN::Options::()", XS_PlPN_nil, file, "$$$");

=head1 METHODS

=over

=item SetZ<>($group, $name, $value)

=item GetZ<>($group, $name, $default)

Sets or gets a setting. C<$group> is optional during a group operation. (See
L</BeginGroupOperation>.)

A group can be any text string. Programmer's Notepad defines several
built-in groups, which are exposed via the C<:OptionsGroup> tag in
L<PlPN|PlPN>. These constants are:

=over

=item PNSK_MRU

=item PNSK_MRUP

=item PNSK_INTERFACE

=item PNSK_EDITOR

=item PNSK_PRINT

=item PNSK_DEFGUI

=item PNSK_FIND

=item PNSK_SCHEMES

=item PNSK_GENERAL

=back

C<$default> is B<not> optional. The reason for this is that this is a
wrapper for an overloaded C++ function, and the type of the value is
required in order for C++ to be able to determine which version of the
function to call.

If there is any doubt, you can make sure your strings are interpreted as
strings by quoting them, you can make sure your numbers are interpretd as
numbers by adding C<0> to them, and you can make sure your Booleans are
interpreted as Booleans by using the constants B<TRUE> and B<FALSE> provided
via L<PlPN|PlPN>:

	$om->Set($group, $name, "$value");
	$om->Get($group, $name, "$default");
	$om->Set($group, $name, $value+0);
	$om->Get($group, $name, $default+0);
	$om->Set($group, $name, $value ? TRUE : FALSE);
	$om->Get($group, $name, $default ? TRUE : FALSE);

The reason for this is because it was considered more important to have a
simple Perl interface, with two methods instead of six (i.e., a setter and
a getter for each of string, number, and Boolean). Perl will usually guess
right betwee strings and numbers, so the precautionary measures will usually
be unnecessary, except for Booleans.

B<Important note about Boolean values>: Do not assume you can substitute
C<1> for Boolean true and C<0> for Boolean false. While this will work if
the settings are stored in the Windows registry, it will not work if the
settings are stored in XML, which uses the strings C<true> and C<false> to
represent those values.

If you are going to use Boolean values, especially for settings used by
other parts of Programmer's Notepad, use B<TRUE> and B<FALSE>. This will
guarantee that the XS code properly interprets the value before calling the
C++ function.

=cut

void
extensions::IOptions::Set(THIS, ...)
	PREINIT:
		const wchar_t* group = NULL;
		const wchar_t* name;
	CODE:
		if (items < 3 || items > 4)
		   croak_xs_usage(cv,  "THIS[, group (may be omitted during group operation)], name, value");
		
		int i = 1;
		SV* ST_i__null;
		if (items == 4) {
			ST_i__null = sv_mortalcopy(ST(i));
			sv_catpvn(ST_i__null, "\0", 1);
			group = (const wchar_t*)utf8_2_wide(SvPV_nolen(ST_i__null));
			i++;
		}
		ST_i__null = sv_mortalcopy(ST(i));
		sv_catpvn(ST_i__null, "\0", 1);
		name = (const wchar_t*)utf8_2_wide(SvPV_nolen(ST_i__null));
		i++;
		
		if (ST(i) == &PL_sv_undef)
			alert("value may not be undef");
		if (ST(i) == &PL_sv_yes || ST(i) == &PL_sv_no) {
			bool bVal = (bool)SvTRUE(ST(i));
			THIS->Set(group, name, bVal);
		}
		else if (SvPOK(ST(i))) {
			ST_i__null = sv_mortalcopy(ST(i));
			sv_catpvn(ST_i__null, "\0", 1);
			wchar_t* szVal = (wchar_t *)utf8_2_wide(SvPV_nolen(ST_i__null));
			THIS->Set(group, name, szVal);
			// caller responsible for freeing memory after utf8_2_wide
			free((void*)szVal);
		}
		else {	// assume integer
			int	iVal = (int)SvIV(ST(i));
			THIS->Set(group, name, iVal);
		}
		
		// caller responsible for freeing memory after wide_2_utf8
		if (items == 4) {
			free((void*)group);
		}
		free((void*)name);

SV*
extensions::IOptions::Get(THIS, ...)
	PREINIT:
		const wchar_t* group = NULL;
		const wchar_t* name;
	CODE:
		if (items < 3 || items > 4)
		   croak_xs_usage(cv,  "THIS[, group (may be omitted during group operation)], name, value");
		
		int i = 1;
		SV* ST_i__null;
		if (items == 4) {
			ST_i__null = sv_mortalcopy(ST(i));
			sv_catpvn(ST_i__null, "\0", 1);
			group = (const wchar_t*)utf8_2_wide(SvPV_nolen(ST_i__null));
			i++;
		}
		ST_i__null = sv_mortalcopy(ST(i));
		sv_catpvn(ST_i__null, "\0", 1);
		name = (const wchar_t*)utf8_2_wide(SvPV_nolen(ST_i__null));
		i++;
		
		if (ST(i) == &PL_sv_undef)
			alert("default may not be undef");
		if (ST(i) == &PL_sv_yes || ST(i) == &PL_sv_no) {
			bool bDefault = (bool)SvTRUE(ST(i));
			RETVAL = boolSV(THIS->Get(group, name, bDefault));
		}
		else if (SvPOK(ST(i))) {
			ST_i__null = sv_mortalcopy(ST(i));
			sv_catpvn(ST_i__null, "\0", 1);
			wchar_t* szDefault = (wchar_t *)utf8_2_wide(SvPV_nolen(ST_i__null));
			wchar_t* retval = THIS->GetS(group, name, szDefault);
			char* converted = (char*)wide_2_utf8(retval);
			RETVAL = newSVpv(converted, 0);	// copies the string
			// caller responsible for freeing memory after utf8_2_wide and wide_2_utf8
			free((void*)szDefault);
			free((void*)converted);
			// strings from PN must be released via ReleaseString
			my_pn->ReleaseString(retval);
		}
		else {	// assume integer
			int	iDefault = (int)SvIV(ST(i));
			RETVAL = newSViv(THIS->Get(group, name, iDefault));
		}
		
		// caller responsible for freeing memory after wide_2_utf8
		if (items == 4) {
			free((void*)group);
		}
		free((void*)name);
	OUTPUT:
		RETVAL

=item GetPNPathZ<>($pathtype = PNPATH_PN)

Retrieves the given path. Path type constants are available via the
C<:PNPath> tag in L<PlPN|PlPN>. These constants are:

=over

=item PNPATH_PN

=item PNPATH_SCHEMES

=item PNPATH_CLIPS

=item PNPATH_TOOLS

=item PNPATH_TAGGERS

=item PNPATH_PROJECTTEMPLATES

=item PNPATH_PRESETS

=item PNPATH_USERMIN

=item PNPATH_USERSETTINGS

=item PNPATH_USERTOOLS

=item PNPATH_COMPILEDSCHEMES

=item PNPATH_USERCLIPS

=back

=cut

wchar_t*
extensions::IOptions::GetPNPath(pathtype = PNPATH_PN)
		int pathtype;
	CLEANUP:
		// strings from PN must be released via ReleaseString
		my_pn->ReleaseString(RETVAL);

=item GetCachedZ<>($option)

=item SetCachedZ<>($option, $value)

Gets or sets one of the cached options. Cached options are read into memory
by Programmer's Notepad, so getting and setting them does not require
reading from or writing to disk. Cahced options constants are available via
the C<:PNPath> tag in L<PlPN|PlPN>. These constants are:

=over

=item OUseTabs

=item OTabWidth

=item OShowIndentGuides

=item OLineNumbers

=item OMaximiseNew

=item OShowFullPath

=item OLineHighlight

=item OWordWrap

=item ORightGuide

=item ORightColumn

=item OLineHighlightColour

=item ORightGuideColour

=item OLineEndings

=item OAlreadyOpenDropAction

=item OAlreadyOpenAction

=item ODefaultCodePage

=item ODefaultScintillaCache

=item OFindAlphaEnabled

=item OFindAlphaPercent

=item OVisibleLineEndings

=item OVisibleWhiteSpace

=item OManageTabOrder

=item OConvertLinesOnPaste

=item ODefaultCharSet

=item OAutoComplete

=item OAutoCompleteUseKeywords

=item OAutoCompleteUseTags

=item OAutoCompleteStartChars

=item OAutoCompleteActivation

=item OAutoCompleteTags

=item OLineHighlightAlpha

=item OFoldingEnabled

=item OCaretXMove

=item OCaretYMove

=item OCaretXFlags

=item OCaretYFlags

=item OSmartHighlight

=item OLinePaddingTop

=item OLinePaddingBottom

=item ODefaultEncoding

=item OMultiByteCodePage

=back

Z<>

=cut

int
extensions::IOptions::GetCached(option)
		extensions::IOptions::ECachedOption option;

void
extensions::IOptions::SetCached(option, value)
		extensions::IOptions::ECachedOption option;
		int value;

=item BeginGroupOperationZ<>($group)

=item EndGroupOperationZ<>()

Begins or ends a group operation. Groups are described under L</Set>.

=cut

void
extensions::IOptions::BeginGroupOperation(group)
		const wchar_t* group;
	CLEANUP:
		// caller responsible for freeing memory after utf8_2_wide
		free((void*)group);

void
extensions::IOptions::EndGroupOperation()

=item GetSearchOptionsZ<>()

Gets the global search options, a L<PlPN::SearchOptions|PlPN::SearchOptions>
object.

See also L<PlPN::PN::GetUserSearchOptions|PlPN::PN/GetUserSearchOptions>.

=cut

extensions::ISearchOptions*
extensions::IOptions::GetSearchOptions()
		const char* CLASS = "PlPN::SearchOptions";

=back

=head1 COPYRIGHT and LICENCE

Copyright (c) 2012 Sean Healy. All rights reserved.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

=cut
